<?php

namespace doc\caching;

class FileCache
{
    /**
     * @var FileCache
     * @name 缓存目录
     */
    private static $cacheDir = null;

    /**
     * @var FileChche
     * @name 文件后缀名
     */
    private static $suffix = '.bin';

    /**
     * @var FileChche
     * @name  是否加密数据
     */
    private static $encrypt  = false;

    /**
     * @var string
     * @name 加密密钥
     */
    private static $key  = 'yanglqiang98365207';

    public function __construct()
    {
        self::$cacheDir = __DIR__.'/cache/';
    }

    /**
     * 设置加密
     * @param $encrypt
     */
    public function setEncrypt($encrypt=true)
    {
        self::$encrypt = $encrypt;

        return $this;
    }

    /**设置缓存
     * @param $key
     * @param $value
     * @param $expire
     */
    public function set($key, $value, $expire=0)
    {
        $data = self::$encrypt ? self::passport_encrypt(serialize($value)) : serialize($value);
        return $this->setValue($key, $data, $expire);
    }

    /**
     * 获取缓存
     * @param $key
     */
    public function get($key)
    {
        $list = $this->getValue($key);
        if ($list !== false) {
            return self::$encrypt ? unserialize(self::passport_decrypt($list)) :unserialize($list);
        } else {
            return false;
        }
    }

    /**
     * 设置数据
     * @param $key
     * @param $value
     * @param int $expire
     * @return bool
     */
    private function  setValue($key, $value, $expire=0)
    {
        $fileName = self::$cacheDir.md5($key).self::$suffix;
        //保存一年
        if ($expire  <= 0) {
            $expire = time()+12*24*3600;
        }

        if (file_exists($fileName)) {
            //获取
            $res = $this->get($key);
            if (md5($value)===md5($res)) {
                return true;
            }
        }

        if (!is_dir(self::$cacheDir)) {
            mkdir(self::$cacheDir, 0777);
        }

        //写入数据：
        $fp = fopen($fileName, 'w+');
        fwrite($fp, $value);
        fclose($fp);
        //设置访问时间：
        @touch($fileName, $expire);
    }

    //获取数据：
    private function  getValue($key)
    {
        $fileName = self::$cacheDir.md5($key).self::$suffix;
        //是否过期:文件是否存在
        if (file_exists($fileName) && filemtime($fileName) > time()) {
            $fp = fopen($fileName, 'r');
            if ($fp !== false) {
                //要取得共享锁定（读取的程序）
                flock($fp, LOCK_SH);
                $data = stream_get_contents($fp);
                //释放锁定
                flock($fp, LOCK_UN);
                fclose($fp);
                return $data;
            }
        }
        return false;
    }

    /**
     * 判断是否有缓存文件
     * @param $key
     * @return bool
     */
    public function has($key)
    {
        return $this->getValue($key) ? true : false;
    }

    /**
     * 加密
     * @param $txt
     * @param $key
     * @return string
     */
    public static function  passport_encrypt($txt)
    {
        $key = self::$key;
        srand((double)microtime() * 1000000);
        $encrypt_key = md5(rand(0, 32000));
        $ctr = 0;
        $tmp = '';
        for ($i = 0; $i < strlen($txt); $i++) {
            $ctr = $ctr == strlen($encrypt_key) ? 0 : $ctr;
            $tmp .= $encrypt_key[$ctr] . ($txt[$i] ^ $encrypt_key[$ctr++]);
        }
        return base64_encode(self::passport_key($tmp, $key));
    }

    /**
     * 解密
     * @param $txt
     * @param $key
     * @return string
     */
    public static function passport_decrypt($txt)
    {
        $key = self::$key;
        $txt = self::passport_key(base64_decode($txt), $key);
        $tmp = '';
        for ($i = 0; $i < strlen($txt); $i++) {
            $md5 = $txt[$i];
            $tmp .= $txt[++$i] ^ $md5;
        }
        return $tmp;
    }

    /**
     * 设置密钥
     * @param $txt
     * @param $encrypt_key
     * @return string
     */
    public static function passport_key($txt, $encrypt_key)
    {
        $encrypt_key = md5($encrypt_key);
        $ctr = 0;
        $tmp = '';
        for ($i = 0; $i < strlen($txt); $i++) {
            $ctr = $ctr == strlen($encrypt_key) ? 0 : $ctr;
            $tmp .= $txt[$i] ^ $encrypt_key[$ctr++];
        }
        return $tmp;
    }

    /**
     * @ 加密（简单的）
     * @var str 加密的字符串
     * @var secret 加密的的秘钥
     * @var url 可用于url传输
     */
    public static function encrypt($str, $secret='yangliqiang', $url = false)
    {
        $key = md5($secret);
        $position = 0;
        //字符串长度
        $len = (int)strlen($str);
        //秘钥长度
        $secretLen = (int)strlen($key);
        //获取秘钥的一部分
        $char = '';
        for ($i=0; $i <$len ; $i++) {
            if ($position===$secretLen) {
                $position = 0;
            }

            $char .= $key{$position};
            $position++;
        }

        //开始组合加密字符
        $encryptStr = '';
        for ($k=0; $k < $len ; $k++) {
            $encryptStr .= chr(ord($str{$k}) + (ord($char{$k})) % 256);
        }
        if (!$url) {
            return base64_encode($encryptStr);
        }

        return rtrim(strtr(base64_encode($encryptStr), '+/', '-_'), '=');
    }

    /**
     * @ 解密（简单的）
     * @var str 加密的字符串
     * @var secret 加密的的秘钥
     * @var url url传输替换字符
     */
    public static function decrypt($string, $secret='zhongqipei',$url = false)
    {
        $key = md5($secret);
        $position = 0;
        $data = !$url ? base64_decode($string) : base64_decode(str_pad(strtr($string, '-_', '+/'), strlen($string) % 4, '=', STR_PAD_RIGHT));

        $len = (int)strlen($data);
        $secretLen = (int)strlen($key);

        //解密秘钥
        $char = '';
        for ($i = 0; $i < $len; $i++)  {
            if ($position === $secretLen)  {
                $position = 0;
            }
            $char .= substr($key, $position, 1);

            $position++;
        }

        //解密
        $str = '';
        for ($k = 0; $k < $len; $k++) {
            if (ord(substr($data, $k, 1)) < ord(substr($char, $k, 1))) {
                $str .= chr((ord(substr($data, $k, 1)) + 256) - ord(substr($char, $k, 1)));
            } else {
                $str .= chr(ord(substr($data, $k, 1)) - ord(substr($char, $k, 1)));
            }
        }

        return $str;
    }



}